package test.spring;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;

public class ExtTransactionSynchronization extends TransactionSynchronizationAdapter {

	private static final Log logger = LogFactory.getLog(ExtTransactionSynchronization.class);

	private static final ThreadLocal<List<SynchronizationHandler>> handlers = new ThreadLocal<List<SynchronizationHandler>>();

	private ExecutorService executor;

	@Override
	public void afterCompletion(int status) {
		try {
			List<SynchronizationHandler> hs = handlers.get();
			if (hs != null && !hs.isEmpty()) {
				for (SynchronizationHandler h : hs) {
					if (status == h.status) {
						final SynchronizationHandler ch = h;
						Future<Void> future = executor.submit(new Callable<Void>() {

							@Override
							public Void call() throws Exception {
								if (ch.runnables != null) {
									for (Runnable runnable: ch.runnables) {
										try {
											runnable.run();
										} catch (Exception ignore) {
											logger.warn("执行事务同步处理时发生异常", ignore);
										}
									}
								}
								
								return null;
							}
						});
						
						try {
							future.get();
						} catch (Exception e) {
							logger.warn("执行事务同步处理的处理进程发生异常", e);
						}
						
					}
				}
			}
		} finally {
			logger.debug("clear handlers");
			handlers.remove();
		}
	}

	public static void addHandler(SynchronizationHandler handler) {
		List<SynchronizationHandler> hs = handlers.get();
		if (hs == null) {
			hs = new ArrayList<SynchronizationHandler>();
			handlers.set(hs);
		}
		hs.add(handler);
	}

	public static class SynchronizationHandler {

		private final int status;
		private final List<Runnable> runnables;

		/**
		 * @param runnable
		 */
		public SynchronizationHandler(List<Runnable> runnables) {
			super();
			this.status = TransactionSynchronizationAdapter.STATUS_COMMITTED;
			this.runnables = runnables;
		}

		/**
		 * @param runnable
		 */
		public SynchronizationHandler(int status, List<Runnable> runnables) {
			super();
			this.status = status;
			this.runnables = runnables;
		}

	}

	/**
	 * @param executor the executor to set
	 */
	public void setExecutor(ExecutorService executor) {
		this.executor = executor;
	}
	
}
